/**
 * 
 */
package edu.gatech.oad.mule.model;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;

import javax.swing.Timer;

import edu.gatech.oad.mule.Game;
import edu.gatech.oad.mule.Map;
import edu.gatech.oad.mule.Player;
import edu.gatech.oad.mule.Tile;
import edu.gatech.oad.mule.TownMap;
import edu.gatech.oad.mule.WorldMap;
import edu.gatech.oad.mule.input.InputEvent;
import edu.gatech.oad.mule.input.interfaces.ControllerOwner;
import edu.gatech.oad.mule.model.GameStateMachine.GameState;
import edu.gatech.oad.mule.view.interfaces.RenderableMap;
import edu.gatech.oad.mule.view.interfaces.RenderablePlayer;
import edu.gatech.oad.mule.view.interfaces.RenderableTile;

/**
 * ProductionPhase handles the logic for a single round's production phase.
 * 
 * @author Dale Avery
 * 
 */
final class ProductionPhase extends Phase {

	private static final long serialVersionUID = 7650118859883139463L;

	public static final GameState STATE = GameState.PRODUCTION;
	private static final int TIMER_PERIOD = 2000;

	private ArrayList<Player> remainingPlayers;
	private Player currentPlayer;
	
	private Timer timer;
	private transient ActionListener listener;
	
	/**
	 * Constructs a new ProductionPhase.
	 * 
	 * @param game
	 *            Object used to obtain relevant information for phase.
	 */
	public ProductionPhase(Game game) {
		super(game);

		// Initialize timer for controlling turns
		timer = new Timer(TIMER_PERIOD, null);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.input.interfaces.InputListener#inputEventHandler(
	 * edu.gatech.oad.mule.input.InputEvent)
	 */
	@Override
	public void inputEventHandler(InputEvent event) {
		// Input is not handled in this phase.
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.gatech.oad.mule.input.interfaces.InputListener#getActiveOwners()
	 */
	@Override
	public ControllerOwner[] getActiveOwners() {
		// There are no controller owners in this phase.
		return new ControllerOwner[0];
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getAllPlayers()
	 */
	@Override
	public RenderablePlayer[] getAllPlayers() {
		// No harm in returning all players in this phase.
		return game.getPlayers();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getCurrentMap()
	 */
	@Override
	public RenderableMap getCurrentMap() {
		// No map in this phase.
		return null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getCurrentPlayer
	 * ()
	 */
	@Override
	public RenderablePlayer getCurrentPlayer() {
		return currentPlayer;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getRankedPlayers
	 * ()
	 */
	@Override
	public RenderablePlayer[] getRankedPlayers() {
		// Player ranking is not really used in this phase.
		return game.getRankedPlayers();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getRemainingTime
	 * ()
	 */
	@Override
	public int getRemainingTime() {
		// Not relevant in this phase.
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getTurnLength()
	 */
	@Override
	public int getTurnLength() {
		// Not relevant in this phase.
		return 0;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * edu.gatech.oad.mule.view.interfaces.RenderableGameDriver#getCurrentTile()
	 */
	@Override
	public RenderableTile getCurrentTile() {
		// Not relevant in this phase.
		return null;
	}

	/**
	 * Transitions from current player to next player in the ranked player list.
	 * Ends the phase once all players have had a turn.
	 */
	private void nextPlayer() {
		if (!remainingPlayers.isEmpty()) {
			currentPlayer = remainingPlayers.remove(0);
			
			// Calculate the production for each player.
			((TownMap)game.getTownMap()).production();
			((WorldMap)game.getWorldMap()).production(game.getPlayers());
		} else {
			stop();
			endPhase();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.gatech.oad.mule.model.Phase#start()
	 */
	@Override
	public void start() {
		// Configure player information (if necessary).
		if (remainingPlayers == null) {
			remainingPlayers = new ArrayList<Player>(Arrays.asList(game
					.getPlayers()));
		}
		if (currentPlayer == null) {
			nextPlayer();
		}

		// Configure timer.
		if (listener == null) {
			listener = new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					checkTime();
				}
			};
		}

		// Only add the action listener if it isn't already added.
		if (timer.getActionListeners().length == 0)
			timer.addActionListener(listener);

		timer.start();
		active = true;
	}
	
	/**
	 * Handles transitions to next tiles on the map and transitions between
	 * players.
	 */
	private void checkTime() {
		nextPlayer();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.gatech.oad.mule.model.Phase#stop()
	 */
	@Override
	public void stop() {
		// Stop the timer to pause the phase.
		active = false;
		timer.stop();
		// Remove action listeners for serialization.
		for (ActionListener l : timer.getActionListeners())
			timer.removeActionListener(l);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.gatech.oad.mule.model.Phase#reset()
	 */
	@Override
	public void reset() {
		// Reset the timer.
		stop();
		timer.restart();

		// Destroy existing phase data.
		remainingPlayers = null;
		currentPlayer = null;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see edu.gatech.oad.mule.model.Phase#getCorrespondingState()
	 */
	@Override
	public GameState getCorrespondingState() {
		return STATE;
	}

}
